home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Magnum One
/
Magnum One (Mid-American Digital) (Disc Manufacturing).iso
/
d13
/
pcrjan89.arc
/
AUTOKEY.ASM
next >
Wrap
Assembly Source File
|
1990-03-21
|
14KB
|
554 lines
comment |
This program reads a file of keystrokes into a buffer and uses them
to replace keyboard input until the buffer is empty.
Written for MASM 5.1 (should compile with earlier versions)
Save as AUTOKEY.ASM
Compile: MASM AUTOKEY;
LINK AUTOKEY; (ignore stack segment warning)
EXE2BIN AUTOKEY.EXE AUTOKEY.COM
|
CR equ 0dh ;Definitions for
LF equ 0ah ; the program's use
TAB equ 09h
code_seg segment
assume cs:code_seg, ds:code_seg, es:code_seg
org 100h ;.COM file format
start: jmp begin
;---------
; Data used by the
; memory-resident portion of
; the program.
;---------
kbd_head equ 1ah
kbd_tail equ 1ch
kbd_start equ 80h
kbd_end equ 82h
int8_gate db ?
old_08 dd ?
old_09 dd ?
save_ss dw ?
save_sp dw ?
dw 50h dup (?)
our_stack equ $-2
buf_ptr dw offset keybuf
buf_count dw 0
BUF_SIZE equ 500 ;Change to suit your needs
keybuf db BUF_SIZE dup (?)
;---------
; Keyboard Interrupt 09 hex
; While keys are being sent
; to the buffer from Autokey,
; disable the physical keyboard
; by simply ignoring all keystrokes
;---------
new_int09 proc far
test cs:buf_count,-1 ;Are we sending keystrokes?
jz orig_int9 ;No -- go
push ax ;Else save AX
in al,60h ;Read the keystroke
in al,61h ;Get Port B value
or al,80h ;Set high bit
out 61h,al ;Send it out
and al,7fh ;Clear high bit
out 61h,al ;We said we received it
mov al,20h ;Signal end of
out 20h,al ; hardware interrupt
pop ax ;Recover original AX
iret ;Key is swallowed
orig_int9:
jmp dword ptr cs:[old_09] ;Use original code for Int 9
new_int09 endp
;---------
; Timer Interrupt
; This is where we stuff the
; keyboard buffer
;---------
new_int08 proc far
pushf ;Simulate an interrupt call
call dword ptr cs:[old_08] ;Hand off to previous code
test cs:buf_count,-1 ;Anything to stuff
jz new8_out ;No -- leave immediately
test cs:int8_gate,-1 ;Okay to execute?
jz stuff_keys
new8_out:
iret ;Return to interrupted program
stuff_keys:
;------
; Set the gate flag.
; switch stacks, and save
; necessary registers.
;------
mov cs:int8_gate,-1 ;Don't allow recursive calls
push ax ;Save caller's AX
mov cs:[save_ss],ss ;Save caller's stack
mov cs:[save_sp],sp
cli ;Interrupts off to switch stack
mov ax,cs ;Get our segment
mov ss,ax ; in SS
mov sp,offset our_stack ;Move to our stack
and sp,0fffeh ;Make sure it's even
sti ;Interrupts on now
push ds ;Save caller's segments
push es
mov ds,ax ;Point to our segment
push di ;Now save registers we need
push si
push bx
mov ax,40h ;Segment for BIOS buffer
mov es,ax ;ES ==> BIOS segment
mov di,es:[kbd_head] ;Get head of buffer
mov bx,es:[kbd_tail] ; and the tail
cmp di,bx ;Is buffer empty?
jne end_stuff ;No -- forget it
mov si,[buf_ptr] ;DS:SI ==> head of our buffer
lodsw ;Get next word
mov [buf_ptr],si ;Save new pointer
dec [buf_count] ;Count this keystroke
or ax,ax ;Is keystroke null?
jz end_stuff ;Yes -- don't stuff it
stosw ;Else put it in buffer
inc bx ;Move tail pointer
inc bx
cmp bx,es:[kbd_end] ;Past the end?
jl dont_wrap ;No -- go
mov bx,es:[kbd_start] ;Get start of key buffer
dont_wrap:
mov es:[kbd_tail],bx ;Save new value
end_stuff:
pop bx ;Clear our stack
pop si
pop di
pop es
pop ds
cli ;Interrupts off to
mov ss,cs:[save_ss] ; switch stacks
mov sp,cs:[save_sp]
pop ax ;All done
mov cs:int8_gate,0 ;Let next call in
jmp new8_out ;And leave
new_int08 endp
res_code equ $ - new_int08
res_size equ $-start
;---------
; Installation code
; and file parsing.
; Everything from here to the end
; is discarded when the TSR is installed
;---------
;---------
; Transient Data
;---------
temp_buf db BUF_SIZE * 2 dup (0)
hello db CR,"AUTOKEY Automatic Keyboard Entry",CR,LF,"$"
bad_ver db "This program requires DOS 2.0 or later",CR,LF,"$"
no_file db "Usage: AUTOKEY keyfile",CR,LF,"$"
no_open db "Cannot open keystroke file",CR,LF,"$"
bad_read db "Error reading keystroke file",CR,LF,"$"
too_large db "Keystroke file is too larger",CR,LF,"$"
installed db "Program and keystrokes installed in memory",CR,LF,"$"
reloaded db "Keystroke buffer reloaded",CR,LF,"$"
first_byte db ? ;For 1st of 2-byte code
code_table dw "cA",1e01h ;Control keys
dw "cB",3002h
dw "cC",2e03h
dw "cD",2004h
dw "cE",1205h
dw "cF",2106h
dw "cG",2207h
dw "cH",2308h
dw "cI",1709h
dw "cJ",240ah
dw "cK",250bh
dw "cL",260ch
dw "cM",320dh
dw "cN",310eh
dw "cO",180fh
dw "cP",1910h
dw "cQ",1011h
dw "cR",1312h
dw "cS",1f13h
dw "cT",1414h
dw "cU",1615h
dw "cV",2f16h
dw "cW",1117h
dw "cX",2d18h
dw "cY",1519h
dw "cZ",2c1ah
dw "aA",1e00h ;Alt keys
dw "aB",3000h
dw "aC",2e00h
dw "aD",2000h
dw "aE",1200h
dw "aF",2100h
dw "aG",2200h
dw "aH",2300h
dw "aI",1700h
dw "aJ",2400h
dw "aK",2500h
dw "aL",2600h
dw "aM",3200h
dw "aN",3100h
dw "aO",1800h
dw "aP",1900h
dw "aQ",1000h
dw "aR",1300h
dw "aS",1f00h
dw "aT",1400h
dw "aU",1600h
dw "aV",2f00h
dw "aW",1100h
dw "aX",2d00h
dw "aY",1500h
dw "aZ",2c00h
dw "F1",3b00h ;Function keys
dw "F2",3c00h
dw "F3",3d00h
dw "F4",3e00h
dw "F5",3f00h
dw "F6",4000h
dw "F7",4100h
dw "F8",4200h
dw "F9",4300h
dw "Ft",4400h
dw "Fe",8500h
dw "Fv",8600h
dw "s1",5400h ;Shift Function keys
dw "s2",5500h
dw "s3",5600h
dw "s4",5700h
dw "s5",5800h
dw "s6",5900h
dw "s7",5a00h
dw "s8",5b00h
dw "s9",5c00h
dw "st",5d00h
dw "se",8700h
dw "sv",8800h
dw "c1",5e00h ;Control Function keys
dw "c2",5f00h
dw "c3",6000h
dw "c4",6100h
dw "c5",6200h
dw "c6",6300h
dw "c7",6400h
dw "c8",6500h
dw "c9",6600h
dw "ct",6700h
dw "ce",8900h
dw "cv",8a00h
dw "a1",6800h ;Alt function keys
dw "a2",6900h
dw "a3",6a00h
dw "a4",6b00h
dw "a5",6c00h
dw "a6",6d00h
dw "a7",6e00h
dw "a8",6f00h
dw "a9",7000h
dw "at",7100h
dw "ae",8b00h
dw "av",8c00h
dw "a!",7800h ;Alt-numbers
dw "a@",7900h
dw "a#",7a00h
dw "a$",7b00h
dw "a%",7c00h
dw "a^",7d00h
dw "a&",7e00h
dw "a*",7f00h
dw "a(",8000h
dw "a)",8100h
dw "t1",9800h ;Tandy 1000 F11 & F12
dw "t2",9900h
dw "!1",0a200h ; (shifted)
dw "!2",0a300h
dw "^1",0ac00h ; (control)
dw "^2",0ad00h
dw "~1",0b600h ; (alt)
dw "~2",0b700h
dw "HM",4700h ;Home
dw "UA",4800h ;Up-arrow
dw "PU",4900h ;Page Up
dw "LA",4b00h ;Left Arrow
dw "RA",4d00h ;Right Arrow
dw "EN",4f00h ;End
dw "DA",5000h ;Down Arrow
dw "PD",5100h ;Page down
dw "IN",5200h ;Insert
dw "DL",5300h ;Delete
dw "CR",1c0dh ;Return/Enter
dw "Tb",0f09h ;Tab
dw "BK",0e08h ;Backspace
dw "sb",0f00h ;Shift-Tab
dw "ES",011bh ;Escape
dw "P+",4e2bh ;Pad Plus
dw "P-",4a2dh ;Pad Minus
dw "ch",7700h ;Ctrl-home
dw "cu",8400h ;Ctrl-up
dw "cl",7300h ;Ctrl-left
dw "cr",7400h ;Ctrl-right
dw "ce",7500h ;Ctrl-end
dw "cd",7600h ;Ctrl-down
dw "NL",0000h ;Null
code_len equ $-code_table ;Length of the table
begin: lea dx,hello ;DS:DX ==> opening message
mov ah,9 ;Print the message
int 21h
mov ah,30h ;Get DOS version
int 21h
cmp al,2 ;At least version 2?
jae version_ok ;Yes -- go
lea dx,bad_ver ;Else report error & leave
jmp error
version_ok:
mov ax,3508h ;Get location of Int 08h
int 21h
mov word ptr [old_08],bx ;Save the address
mov word ptr [old_08+2],es ; in ES:BX
mov ax,3509h ;Get location of Int 09h
int 21h
mov word ptr [old_09],bx ;Save the address
mov word ptr [old_09+2],es ; in ES:BX
lea di,new_int09 ;Get code start address in DI
mov si,di ;Copy to SI
mov cx,res_code ;Bytes to compare
repz cmpsb ;Are we already installed?
jz read_file ;Yes -- go
push ds ;Else move ES
pop es ; to this segment
read_file:
mov es:buf_count,0 ;Turn off any output
lea dx,no_file ;Ready for possible error
mov si,80h ;DS:SI ==> command tail in PSP
lodsb ;Get length of tail
or al,al ;Anything there?
jnz read_1 ;Yes -- go
jmp error ;Else report error & leave
read_1:
lodsb ;Get a character
cmp al,' ' ;Is it a space?
je read_1 ;Yes -- skip it
cmp al,TAB ;Is it a tab?
je read_1 ;Yes -- skip it
mov di,si ;Save this position
dec di ;DI ==> beginning of file name
read_2:
lodsb ;Get next character
cmp al,' ' ;At end of file name?
jg read_2 ;No -- loop back
dec si ;Yes -- move back to terminator
mov byte ptr [si],0 ;Change terminator to NULL
mov ax,di ;Get offset of beginning
sub ax,si ;Check name length
jnz read_3 ;Go if name exists
jmp error ;Else report error & leave
read_3:
mov dx,di ;DS:DX ==> beginning of name
mov ax,3d00h ;Open file for reading
int 21h ;Try to open file
jnc read_4 ;Go if file was opened
lea dx,no_open ;Else report failure
jmp error ; and leave
read_4:
mov bx,ax ;File handle in BX
lea dx,temp_buf ;DS:DX ==> receiving buffer
mov cx,BUF_SIZE * 2 ;Maximum bytes to read
mov ah,3fh ;Read from file
int 21h
jnc read_5 ;No error -- continue
lea dx,bad_read ;Else report error
jmp error ; and leave
read_5:
push ax ;Save number of bytes read
mov ah,3eh ;Close the file
int 21h
pop bx ;BX = number of bytes read
cmp bx,cx ;Did we get the whole file?
jl read_6 ;Yes -- go
lea dx,too_large ;Else report error
jmp error ; and leave
read_6:
add bx,offset temp_buf ;BX ==> end of input stream
mov byte ptr [bx],0 ;Terminate buffer
lea si,temp_buf ;DS:SI ==> temporary buffer
lea di,keybuf ;ES:DI ==> key buffer
mov cx,0 ;CX will count bytes
mov dl,0 ;DL = in-quotes flag
read_7:
lodsb ;Get byte from input buffer
cmp al,0 ;End of buffer?
jz read_9 ;Yes -- go
cmp al," " ;Less than a space?
jl read_7 ;Yes -- ignore it
call translate ;Else translate to scan code
jz read_8 ;Go if nothing to save
stosw ;Else put in key buffer
inc cx ;Count the key
inc cx ; twice
read_8:
cmp cx,BUF_SIZE * 2 ;Buffer full?
jl read_7 ;No -- get some more
lea dx,too_large ;Else report error
jmp error ; and leave
read_9:
shr cx,1 ;Divide byte count by 2
lea ax,keybuf ;Get start of buffer
mov es:[buf_ptr],ax ;Save start address
mov es:[buf_count],cx ; and keystroke count
mov ax,es ;Get buffer segment
mov bx,ds ;And local segment
cmp ax,bx ;Are they the same?
jne exit ;No -- buffer already installed
lea dx,installed ;Report success
mov ah,09h ;Print a string
int 21h
mov ax,40h ;BIOS data segment
mov es,ax ;Use ES to reach BIOS data
mov ax,es:[kbd_start] ;Is value initialized?
or ax,ax ;Test the value
jnz kbd_ok ;Go if already set
mov ax,1eh ;Else set standard keyboard
mov es:[kbd_start],ax ; buffer in BIOS area
mov es:[kbd_head],ax ;And empty keyboard
mov es:[kbd_tail],ax
mov ax,3eh ;Normal keyboard end
mov es:[kbd_end],ax ;Store that address, also
kbd_ok:
lea dx,new_int08 ;DS:DX ==> new Int 08 routine
mov ax,2508h ;Hook it into Int8 vector
int 21h
lea dx,new_int09 ;DS:DX ==> new Int 09 routine
mov ax,2509h ;Hook it into Int9 vector
int 21h
mov ax,res_size ;Get size to keep
add ax,10fh ;Add PSP and round up
mov cl,4 ;Convert to paragraphs
shr ax,cl ;AX = paragraphs to keep
mov dx,ax ;Size in DX
mov ax,3100h ;Keep resident program
int 21h ;Back to DOS
exit: lea dx,reloaded ;Report using old buffer
mov ah,9 ;Print the string
int 21h
mov al,0 ;Return errorlevel = 0
exit1: mov ah,4ch ;Exit to DOS
int 21h
error: mov ah,9 ;Print error message
int 21h
mov al,0ffh ;Return errorlevel = 255
jmp exit1 ;Back to DOS
;---------
;Translate from the ASCII/human
; format into the appropriate
; ASCII/scancode format for Int 16h
;Receives character from input in AL,
;Returns scan code in AX, ZeroFlag = NZ to save code
; or AX = 0, ZeroFlag = Z to not save the code
;---------
translate proc near
or dl,dl ;In quotes now?
jz no_quote ;No -- go
cmp al,dl ;Ending quotes?
jz end_quote ;Yes -- go
cbw ;Else save character in AL
or ax,ax ;Reset Z-flag
ret
end_quote:
mov dl,0 ;Turn off quotes
xor ax,ax ;Clear AX & set Z-flag
ret
no_quote:
cmp al,'"' ;Beginning quote?
jz start_quote ;Yes -- go
cmp al,"'" ;Beginning single quote?
jz start_quote ;Yes -- go
test first_byte,-1 ;2nd byte of 2-byte command
jnz byte_2 ;Yes -- go
cmp al," " ;White space?
jbe end_quote ;Yes -- skip it
mov first_byte,al ;Else begin 2-byte command
xor ax,ax ;Set AX = 0 & Z-flag
ret
start_quote:
mov dl,al ;Save this quote mark
xor ax,ax ;AX = 0 & Z-flag set
ret
byte_2: ;2nd byte of 2-byte command
mov ah,first_byte ;AX = 2-byte code
mov first_byte,0 ;Erase 1st byte
push cx ;Save our registers
push di
push es
push ds ;Bring ES to this segment
pop es
lea di,code_table ;ES:DI ==> table of codes
mov cx,code_len ;Get length of table to search
shr cx,1 ;Divide by 2
repne scasw ;Scan table for match
jcxz no_match ;Go if no match
mov ax,es:[di] ;Else get scan code
pop es ;Recover registers
pop di
pop cx
push ax ;Save code
or ax,1 ;ZeroFlag = NZ
pop ax ;Recover code
ret
no_match:
pop es ;Recover registers
pop di
pop cx
xor ax,ax ;Set Z-flag
ret
translate endp
code_seg ends
end start